#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef void (*convert_func_t)(uint32_t *data, long n, FILE *fpout);

void convert_coe(uint32_t *data, long n, FILE *fpout)
{
	long i;

	fprintf(fpout, "memory_initialization_radix=16;\n");
	fprintf(fpout, "memory_initialization_vector=\n");
	for (i=0; i<n; i++) {
		fprintf(fpout, "%08x%c\n", data[i], i==n-1?';':',');
	}
}

void convert_mem(uint32_t *data, long n, FILE *fpout)
{
	long i;

	fprintf(fpout, "@00000000\n");
	for (i=0; i<n; i++) {
		fprintf(fpout, "%08x\n", data[i]);
	}
}

void convert_mif(uint32_t *data, long n, FILE *fpout)
{
	char line[34];
	long i;

	line[32] = '\n';
	line[33] = 0;
	for (i=0; i<n; i++) {
		int j;
		for (j=0; j<32; j++)
			line[j] = '0'|((data[i]>>(31-j))&1);
		fputs(line, fpout);
	}
}

int convert(convert_func_t conv, FILE *fpin, FILE *fpout)
{
	long len, len4, n;
	uint32_t *data;

	fseek(fpin, 0, SEEK_END);
	len = ftell(fpin);
	len4 = len+3&~3;
	n = len4>>2;
	fseek(fpin, 0, SEEK_SET);
	data = malloc(len4);
	if (!data) {
		fprintf(stderr, "out of memory\n");
		return 1;
	}
	data[n-1] = 0; // in case file length is not multiple of 4
	if (fread(data, 1, len, fpin) != len) {
		perror("error reading input file");
		return 1;
	}
	conv(data, n, fpout);
	return 0;
}

int main(int argc, char **argv)
{
	FILE *fpin, *fpout;
	char *outfmt_str, *fpathin, *fpathout;
	convert_func_t conv;

	if (argc != 4) {
		fprintf(stderr, "usage?\n");
		return 2;
	}

	outfmt_str = argv[1];
	fpathin  = argv[2];
	fpathout = argv[3];

	if (!strcmp(outfmt_str, "coe")) {
		conv = convert_coe;
	} else if (!strcmp(outfmt_str, "mem")) {
		conv = convert_mem;
	} else if (!strcmp(outfmt_str, "mif")) {
		conv = convert_mif;
	} else {
		fprintf(stderr, "invalid output format: %s\n", outfmt_str);
		return 1;
	}

	fpin = fopen(fpathin, "rb");
	if (!fpin) {
		perror(fpathin);
		return 1;
	}

	fpout = fopen(fpathout, "w");
	if (!fpout) {
		perror(fpathout);
		return 1;
	}

	return convert(conv, fpin, fpout);
}
